package com.derbysoft.ota.application.service.impl;

import static com.derbysoft.remote.dswitch.generic.constants.UniqueIDType.HOTEL;

import java.util.Collection;
import java.util.List;
import java.util.Map.Entry;

import com.derbysoft.modules.eip.translator.Translator;
import com.derbysoft.modules.validation.ValidateUtils;
import com.derbysoft.ota.application.service.CancelService;
import com.derbysoft.ota.application.service.HotelCodeRetriever;
import com.derbysoft.ota.interfaces.protocol._2009a.*;
import com.derbysoft.remote.dswitch.core.GenericRQ;
import com.derbysoft.remote.dswitch.core.GenericRS;
import com.derbysoft.remote.dswitch.core.RequestHeader;
import com.derbysoft.remote.dswitch.generic.dto.UniqueIDDTO;
import com.derbysoft.remote.dswitch.hotel.dswitch.DSwitch4HotelBuyerWebServiceFactory;
import com.derbysoft.remote.dswitch.hotel.dto.CancelRQ;
import com.derbysoft.remote.dswitch.hotel.dto.CancelRS;
import com.google.common.base.Function;
import com.google.inject.Inject;
import com.google.inject.internal.Maps;
import com.googlecode.functionalcollections.FunctionalIterables;

import javax.annotation.Nullable;

public class CancelServiceImpl extends AbstractService implements CancelService {

	private Translator<OTACancelRQ, CancelRQ> rqTranslator;
	private HotelCodeRetriever hotelCodeRetriever;
	private Translator<Entry<CancelRS, OTACancelRS>, OTACancelRS> rsTranslator;

	@Inject
	public CancelServiceImpl(
			DSwitch4HotelBuyerWebServiceFactory dswitch4HotelBuyerWebServiceFactory,
			Translator<POSType, RequestHeader> requestHeaderTranslator,
			Translator<OTACancelRQ, CancelRQ> rqTranslator,
			HotelCodeRetriever hotelCodeRetriever,
			Translator<Entry<CancelRS, OTACancelRS>, OTACancelRS> rsTranslator) {

		super(dswitch4HotelBuyerWebServiceFactory, requestHeaderTranslator);
		this.rqTranslator = rqTranslator;
		this.hotelCodeRetriever = hotelCodeRetriever;
		this.rsTranslator = rsTranslator;
	}

	@Override
	public OTACancelRS make(OTACancelRQ otaCancelRQ) {
		GenericRQ<CancelRQ> genericRQ = switchRequest(otaCancelRQ);

		ValidateUtils.validate(genericRQ);
		GenericRS<CancelRS> genericRS = dswitch().cancelReservation(genericRQ);
		ValidateUtils.validate(genericRS);

		return otaResponse(otaCancelRQ, genericRS);
	}

	private GenericRQ<CancelRQ> switchRequest(OTACancelRQ otaCancelRQ) {
		RequestHeader requestHeader = requestHeader(otaCancelRQ.getPOS(), otaCancelRQ.getUniqueID(), true);
		requestHeader.getProducts().add(new UniqueIDDTO(hotelCodeRetriever.retrieve(otaCancelRQ), HOTEL));
		return new GenericRQ<CancelRQ>(requestHeader, rqTranslator.translate(otaCancelRQ));
	}

	private OTACancelRS otaResponse(OTACancelRQ otaCancelRQ, GenericRS<CancelRS> genericRS) {
		OTACancelRS otaCancelRS = new OTACancelRS();

		if (!handleResponseHeaders(genericRS, otaCancelRQ, otaCancelRS)) {
			otaCancelRS.setStatus(TransactionStatusType.CANCELLED);
			return rsTranslator.translate(Maps.immutableEntry(genericRS.getPayload(), otaCancelRS));
		}

		otaCancelRS.setStatus(TransactionStatusType.UNSUCCESSFUL);
		otaCancelRS.getUniqueID().addAll(uniqueIDs(otaCancelRQ.getUniqueID()));
		return otaCancelRS;
	}

	private Collection<UniqueIDType> uniqueIDs(List<OTACancelRQ.UniqueID> uniqueIDs) {
		return FunctionalIterables.make(uniqueIDs).map(new Function<OTACancelRQ.UniqueID, UniqueIDType>() {
			@Override
			public UniqueIDType apply(@Nullable OTACancelRQ.UniqueID uniqueID) {
				UniqueIDType uniqueIDType = new UniqueIDType();
				uniqueIDType.setID(uniqueID.getID());
				uniqueIDType.setType(uniqueID.getType());
				return uniqueIDType;
			}
		}).toCollection();
	}


}
